package tcp_helper

import (
	"fmt"
	"net"
	"sync"
	"time"
)

const bufExpire = 10 * time.Minute //buf缓存时间
const readBufferSize = 5 * 1024
const writeBufferSize = 5 * 1024
const SendPackageCacheSize = 1000 //每个连接最多缓存发送包的个数

//单个连接数据
type BaseClient struct {
	id                  []byte        //id字段,表连接唯一ID
	conn                net.Conn      //连接
	to_write_pkgs       chan *Package //每个client会保持一份
	readed_pkgs         chan *Package //所有client共同保持一份
	read_buf            []byte        //读临时缓存（读取后解析剩下的）
	write_buf           []byte        //写临时缓存（发送时没发送完的）
	close_time          time.Time     //关闭连接时间
	lock                sync.Mutex    //连接操作锁
	close_conn_callback func()        //关闭连接回调
}

//获取连接
func (cli *BaseClient) GetConn() net.Conn {
	cli.lock.Lock()
	defer cli.lock.Unlock()
	return cli.conn
}

func (cli *BaseClient) SetConn(conn net.Conn) {
	cli.lock.Lock()
	defer cli.lock.Unlock()
	cli.conn = conn
}

//关闭连接，同时将连接置为nil
func (cli *BaseClient) CloseConn() {
	{
		cli.lock.Lock()
		defer cli.lock.Unlock()
		if cli.conn != nil {
			cli.conn.Close() // 关闭连接
			cli.conn = nil
		}
	}
	if cli.close_conn_callback != nil {
		cli.close_conn_callback()
	}
}

//重连后恢复之前的连接数据
func (cli *BaseClient) RecoverClientData(old_cli *BaseClient) {
	//检查老数据是否超时
	if time.Since(old_cli.close_time) < bufExpire {
		//未超时， 复用之前的数据
		cli.to_write_pkgs = old_cli.to_write_pkgs
		cli.read_buf = old_cli.read_buf
		cli.write_buf = old_cli.write_buf
	}
}

func (cli *BaseClient) handleRead() {
	defer cli.CloseConn()

	for {
		conn := cli.GetConn()
		if conn == nil {
			fmt.Println("connection lost")
			break
		}

		var buf [readBufferSize]byte
		n, err := conn.Read(buf[:]) // 读取数据
		if err != nil {
			fmt.Println("read from client failed, err:", err)
			break
		}

		//解析包，并放入通道
		cli.read_buf = append(cli.read_buf, buf[:n]...)
		pkg_lst := UnSerializePackage(&cli.read_buf)
		for i := 0; i < len(pkg_lst); i += 1 {
			cli.readed_pkgs <- pkg_lst[i]
		}
	}
}

func (cli *BaseClient) handleSend() {
	defer cli.CloseConn()

	for {
		if cli.GetConn() == nil {
			fmt.Println("connection lost")
			break
		}
		size := len(cli.to_write_pkgs)
		if size > 0 {
			for len(cli.write_buf) < writeBufferSize && size > 0 {
				pkg := <-cli.to_write_pkgs
				cli.write_buf = append(cli.write_buf, pkg.Serialize()...)
				size -= 1
			}
		} else if len(cli.write_buf) == 0 {
			select {
			case pkg := <-cli.to_write_pkgs:
				cli.write_buf = pkg.Serialize()
			case <-time.After(time.Second):
				continue //超时返回，避免连接断开了还一直在运行
			}
		}

		//上面可能等待，等完后首先检查连接在不在
		conn := cli.GetConn()
		if conn == nil {
			fmt.Println("connection lost")
			break
		}
		//检查好了再写
		n, err := conn.Write(cli.write_buf) // 发送数据
		if err != nil {
			fmt.Println("write to client failed, err:", err)
			break
		}

		cli.write_buf = append(cli.write_buf[:0], cli.write_buf[n:]...)
	}
}

//发送消息 . 返回： 0 成功 -1 连接断开 -2 发送缓存已满
func (cli *BaseClient) Send(id, data []byte) int {
	if cli.GetConn() == nil {
		return -1
	}

	select {
	case cli.to_write_pkgs <- CreatePackage(id, data):
		return 0
	default:
		//队列满了
		return -2
	}
}
